package lt.ntec.danblog.server.blog.model.objectify;

import com.google.appengine.api.datastore.Entity;
import com.googlecode.objectify.Objectify;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.persistence.Id;
import javax.persistence.PostLoad;
import javax.persistence.PrePersist;
import javax.persistence.Transient;
import lt.ntec.danblog.server.blog.model.Post;
import lt.ntec.danblog.server.blog.util.PostUtils;
import lt.ntec.danblog.server.core.model.Comment;
import lt.ntec.danblog.server.core.model.Tag;
import lt.ntec.danblog.server.core.model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class BlogPost implements Post {
    public static final int PREVIEW_STRING_LENGTH = 100;

    private static final Logger LOG = LoggerFactory.getLogger(BlogPost.class);
    private static final String TAG_TYPE = "BlogPost";
    private String title;
    private String content;
    private Date date;

    @Transient
    private Set<? extends Tag> tags;
    
    private Set<Long> tagIds;
    
    @Transient
    private User author;
    private Long authorId;
    private String preview;
    
    @Id
    private Long id;
    private int voteUp;
    private int voteDown;
    private String urlString;
    
    private Set<Long> votedUsers;
    
    @Transient
    private List<Comment> comments = new LinkedList<Comment>();
    
    
    public BlogPost() {
    }
  
    public BlogPost(User user, String urlString) {
        this.author = user;
        this.urlString = urlString;
    }

    @Override
    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public void setContent(String content) {
        this.preview = PostUtils.generatePreviewString(content,
                                                       PREVIEW_STRING_LENGTH);
        this.content = content;
    }

    @Override
    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public void setTags(Set<? extends Tag> tags) {
        this.tags = tags;
    }

    @Override
    public User getAuthor() {
        return author;
    }

    @Override
    public Date getDate() {
        return date;
    }

    @Override
    public String getContent() {
        return content;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public String getPreview() {
        return preview;
    }

    @Override
    public String getUrlString() {
        return urlString;
    }

    @Override
    public Set<? extends Tag> getTags() {
        return tags;
    }

    @Override
    public String getTagString() {
        StringBuilder buff = new StringBuilder();
        for (Tag tag : getTags()) {
            buff.append(tag.getValue()).
                    append(" ");
        }
        if (buff.length() < 2) {
            return "";
        }
        return buff.substring(0, buff.length() - 1);
    }

    @Override
    public Long getId() {
        return id;
    }

    @Override
    public void addComment(Comment comment) {
        this.comments.add(comment);
    }

    @Override
    public List<? extends Comment> getComments() {
        return comments;
    }

    @Override
    public int getVoteUp() {
        return voteUp;
    }

    @Override
    public int getVoteDown() {
        return voteDown;
    }

    @Override
    public void addVoteDown(User user) {
        voteDown++;
        votedUsers.add(user.getId());
    }

    @Override
    public void addVoteUp(User user) {
        voteUp++;
        votedUsers.add(user.getId());
    }

    @Override
    public boolean hasUserVoted(User user) {
        if (votedUsers.contains(user.getId())) {
            return true;
        }
        else return false;
    }

    public Set<Long> getTagIds() {
        return tagIds;
    }

    public void setTagIds(Set<Long> tagIds) {
        this.tagIds = tagIds;
    }

    public Set<Long> getVotedUsers() {
        return votedUsers;
    }

    public void setVotedUsers(Set<Long> votedUsers) {
        this.votedUsers = votedUsers;
    }

    public void setAuthor(User author) {
        this.author = author;
    }

    public Long getAuthorId() {
        return authorId;
    }
    
    @PostLoad
    void load(Objectify ofy, Entity ent) {
        LOG.debug("applying proxies for " + getId());
        
        this.author = ProxyFactory.getInstance().getPostUserProxy(this);
        
        this.tags = ProxyFactory.getInstance().getTagListProxy(this);
        
        this.comments = ProxyFactory.getInstance().getCommentList(this);
        
    }
    
    @PrePersist
    void persist(Objectify ofy, Entity ent) {
        if (author == null) {
            throw new IllegalStateException(
                    "There should be author set before persisting");
        }
        
        if (authorId == null) {
            this.authorId = this.author.getId();
        }
    }

    @Override
    public String getType() {
        return TAG_TYPE;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final BlogPost other = (BlogPost) obj;
        if (this.id != other.id &&
                (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 67 * hash + (this.content != null ? this.content.hashCode() : 0);
        hash = 67 * hash + (this.author != null ? this.author.hashCode() : 0);
        hash = 67 * hash + (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }
    
    
    

}
